package cn.bigfire.compiler.dragon.appendixA.handwrite.lexer;



import java.io.IOException;
import java.util.Hashtable;
import cn.bigfire.compiler.dragon.appendixA.handwrite.symbols.Type;

public class Lexer {
    public static int line = 1;
    char peek = ' ';//空格

    //保留字 表
    Hashtable<String, Word> words = new Hashtable<String, Word>();

    //注册保留字
    public void reserve(Word word) {
        words.put(word.lexeme, word);
    }

    public Lexer() {
        reserve(new Word("if", Tag.IF));
        reserve(new Word("else", Tag.ELSE));
        reserve(new Word("while", Tag.WHILE));
        reserve(new Word("do", Tag.DO));
        reserve(new Word("break'", Tag.BREAK));
        reserve(Word.True);
        reserve(Word.False);
        reserve(Type.Int);
        reserve(Type.Char);
        reserve(Type.Bool);
        reserve(Type.Float);
    }


    public void readch() throws IOException {
        peek = (char) System.in.read();
    }

    public boolean readch(char c) throws IOException {
        readch();//读一个
        if (peek != c) {
            return false;
        }
        peek = ' ';//空格
        return true;
    }

    public Token scan() throws IOException{
        //空 制表符 换行
        for (; ; readch()) {
            if (peek == ' ' || peek == '\t') {//跳过空格 和 制表符
                continue;
            } else if (peek == '\n') {//换行
                line = line + 1;
            } else {
                break;
            }
        }

        //逻辑符号
        switch (peek) {
            case '&':
                if (readch('&')) return Word.and;
                else return new Token('&');
            case '|':
                if (readch('|')) return Word.or;
                else return new Token('|');
            case '=':
                if (readch('=')) return Word.eq;
                else return new Token('=');
            case '!':
                if (readch('=')) return Word.ne;
                else return new Token('!');
            case '<':
                if (readch('=')) return Word.le;
                else return new Token('<');
            case '>':
                if (readch('=')) return Word.ge;
                else return new Token('>');
        }

        //数字
        if (Character.isDigit(peek)) {
            int v = 0;
            do {
                v = 10 * v + Character.digit(peek, 10);
                readch();
            } while (Character.isDigit(peek));

            if (peek != '.') {
                return new Num(v);
            }

            //处理有小数点的
            float x = v;
            float d = 10;
            for (; ; ) {
                readch();
                if (!Character.isDigit(peek)) {
                    break;
                }
                x = x + Character.digit(peek, 10) / d;
                d = d * 10;
            }
            return new Real(x);
        }

        //字符
        if (Character.isLetter(peek)) {
            StringBuilder sb = new StringBuilder();
            do {
                sb.append(peek);
                readch();
            } while (Character.isLetterOrDigit(peek));

            String s = sb.toString();
            Word word = words.get(s);
            if (word != null) {
                return word;
            }
            word = new Word(s, Tag.ID);
            words.put(s, word);
            return word;
        }

        Token token = new Token(peek);
        peek = ' ';
        return token;
    }

}
